﻿using Nemerle.Assertions;
using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.Collections.Generic;
using System.Linq;
using Nemerle2.Compiler;
using Microsoft.Cci;

namespace MetadataReader.CCI
{
  /// <summary>
  /// Description of CciMethodInfo.
  /// </summary>
  class CciMethodInfo : CciMemberInfo, IMethodInfo
  {
    public this([NotNull] declType : CciTypeInfo, definition : IMethodDefinition, index :  int)
    {
      base(declType, definition, index);
    }

    public sealed override Type : FixedType { get { FunType } }

    internal InternedKey : uint
    {
      get //Bogdan TODO: Figure out in witch interface it is defined in CCI and move to base MemberInfo
          //_Eter: this property is defined both in ITypeReference and IMethodReference
      {
        MethodDefinition.InternedKey
      }
    }

    private MethodDefinition : IMethodDefinition { get { Definition :> IMethodDefinition } }

    public override IsAbstract : bool { get { MethodDefinition.IsAbstract } }

    public IsConstructor : bool { get { MethodDefinition.IsConstructor } }

    public override MemberKind : MemberKind
    {
      get { if (IsConstructor) MemberKind.Constructor else MemberKind.Method }
    }

    public override IsStatic : bool { get { MethodDefinition.IsStatic } }

    public FunType : FixedType.Fun
    {
      [Nemerle.Memoize]
      get
      {
        def pars = FixedType.Tuple(Parameters.Map(t => t.Type));
        def ret = Provider.GetType(MethodDefinition.Type);
        FixedType.Fun(pars, ret);
      }
    }
    /// Obtain return type of typed method. If it is already inferred/fixed the value is one of FixedType variant options.
    public ReturnType  : NType
    {
      get
      {
        FunType.to;
      }
    }
    public ParametersType  : FixedType.Tuple
    {
      get
      {
        FunType.from;
      }
    }
    public IsVarArgs : bool { get { throw NotImplementedException() } }
    public FixedParameters : list[Nemerle2.Compiler.IParameterInfo]
    {
    	get
    	{
    	  if(ParameterArray.HasValue)
    		  Parameters.Filter(p => p : object != ParameterArray.Value)
    		else
    		  Parameters
    	}
    }

    public ParameterArray : ValueOption[Nemerle2.Compiler.IParameterInfo]
    {
      [Nemerle.Memoize]
    	get
    	{
    		def paramArray = MethodDefinition.Parameters.FirstOrDefault(p => p.IsParameterArray);
    		match(paramArray)
    		{
    		  | null => ValueOption.None()
    		  | t => ValueOption.Some(CciParameterInfo(Provider,t))
    		}
    	}
    }

    public Parameters : list[Nemerle2.Compiler.IParameterInfo]
    {
      [Nemerle.Memoize]
    	get
    	{
    	  MethodDefinition.Parameters.Map(x => CciParameterInfo(Provider, x) : IParameterInfo )
    	}
    }

    public Return : Nemerle2.Compiler.IInfo
    {
    	get
    	{
    	  Provider.GetTypeInfo(MethodDefinition.Type)
    	}
    }

    public IsFinal     : bool
    {
      get
      {
        MethodDefinition.IsSealed
      }
    }
    public IsExtension : bool
    {
      get
      {
        MethodDefinition.IsExtension()
      }
    }
  }
}
